package com.hzhanghuan.materialsearchview;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.ViewCompat;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.hzhanghuan.materialsearchview.utils.AnimationUtils;

import java.util.Collection;
import java.util.Collections;


/**
 * Material风格的搜索栏
 * Created by Administrator on 2016/7/6.
 */
public class MaterialSearchView extends CoordinatorLayout {


    /**
     * 搜索条
     */
    private LinearLayout mSearchBar;

    /**
     * 这个EditText负责输入搜索文本
     */
    private EditText mSearchView;


    /**
     * 这个ListView为输入提供建议文本
     */
    private ListView mSuggestionsListView;


    /**
     * 这个ImageButton是关闭搜索页面的按钮
     */
    private ImageButton mBackView;

    /**
     * 这个按钮用于清空输入宽的搜索内容
     */
    private ImageButton mClearView;


    /**
     * SearchBar在布局中的位置
     */
    private int mSearchBarIndex = -1;

    /**
     * SuggestionsListView在布局中的位置
     */
    private int mSuggestionsIndex = -2;

    /**
     * 标记是否与AppBarLayout的Elevation值同步
     */
    private boolean mSearchBarElevationEnable = true;

    /**
     * 搜索条阴影值
     */
    private float mSearchBarElevation = 0;

    /**
     * 搜索条高度
     */
    private int mSearchHeight = 0;


    private SearchListener mSearchListener;

    private DataSetObserverImpl mDataSetObserver;





    /**
     * 构造方法
     *
     * @param context
     */
    public MaterialSearchView(Context context) {
        this(context, null);
    }





    /**
     * 构造方法
     *
     * @param context
     * @param attrs
     */
    public MaterialSearchView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }





    /**
     * 构造方法
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MaterialSearchView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //创建搜索功能需要的View
        createSearchView();
        //允许改变ChildView的顺序
        ViewCompat.setChildrenDrawingOrderEnabled(this, true);
        setWillNotDraw(true); // No need to draw until the insets are adjusted
        setSuggestionViewListener(new DefaultSuggestionViewListener());
        mDataSetObserver = new DataSetObserverImpl();

    }





    /**
     * 创建搜索需要的View
     */
    private void createSearchView() {
        Context context = getContext();
        mSearchBar = new LinearLayout(context);
        mSearchView = new EditText(context);
        mClearView = new ImageButton(context);
        mBackView = new ImageButton(context);
        mBackView.setImageResource(R.drawable.ic_arrow_back_grey_600_24dp);
        mClearView.setImageResource(R.drawable.ic_close_grey_600_24dp);
        mSearchBar.setBackgroundColor(Color.WHITE);
        mSearchView.setBackgroundColor(Color.TRANSPARENT);
        mBackView.setBackgroundColor(Color.TRANSPARENT);
        mClearView.setBackgroundColor(Color.TRANSPARENT);
        mSearchView.setGravity(Gravity.CENTER_VERTICAL);
        mSearchBar.setOrientation(LinearLayout.HORIZONTAL);
        mSearchView.setSingleLine();
        displayClear(false);
        mSearchView.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
        ViewCompat.setElevation(mSearchBar, mSearchBarElevation);
        Resources.Theme theme = getContext().getTheme();
        final TypedArray ta = theme.obtainStyledAttributes(new int[]{R.attr.actionBarSize});
        int mSearchWidth = mSearchHeight = ta.getDimensionPixelOffset(0, 56);
        mSuggestionsListView = new ListView(context);
        mSearchBar.addView(mBackView, 0, new LinearLayout.LayoutParams(mSearchWidth, mSearchHeight));
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, mSearchHeight);
        lp.gravity = Gravity.CENTER_VERTICAL;
        lp.weight = 1;
        mSearchBar.addView(mSearchView, 1, lp);
        mSearchBar.addView(mClearView, new LinearLayout.LayoutParams(mSearchWidth, mSearchHeight));
        addView(mSearchBar, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        addView(mSuggestionsListView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        displaySuggestions(false);
        displaySearchBar(false);
        //监听关闭按钮
        mBackView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                closeSearch();
            }
        });
        //监听清除按钮
        mClearView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mSearchView.setText("");
            }
        });
        mSearchView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_SEARCH && mSearchListener != null) {
                    boolean result = mSearchListener.onSearch(MaterialSearchView.this, v.getText().toString());
                    if (result) {
                        closeSearch();
                    }
                    return result;
                }
                return false;
            }
        });
        //监听文本输入
        mSearchView.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }





            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }





            @Override
            public void afterTextChanged(Editable s) {
                displayClear(!TextUtils.isEmpty(s));
                if (mSearchListener != null) {
                    mSearchListener.onEdit(MaterialSearchView.this, s.toString());
                }
            }
        });

    }





    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mSearchBarIndex = -1;
        mSuggestionsIndex = -1;
        //记录mSearchBar和mSuggestionsListView的位置
        mSearchBarIndex = indexOfChild(mSearchBar);
        mSuggestionsIndex = indexOfChild(mSuggestionsListView);
        if (mSearchBarElevationEnable) {
            for (int i = 0; i < getChildCount(); i++) {
                View view = getChildAt(i);
                if (view instanceof AppBarLayout) {
                    ViewCompat.setElevation(mSearchBar, ViewCompat.getElevation(view));
                    break;
                }
            }
        }

    }





    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (mSearchBar.getVisibility() == View.VISIBLE) {
            mSearchBar.layout(0, 0, getWidth(), mSearchHeight);
        }
        if (mSuggestionsListView.getVisibility() == View.VISIBLE) {
            mSuggestionsListView.layout(0, mSearchHeight, getWidth(), getHeight());
        }
    }





    /**
     * 改变子View的默认draw排序
     *
     * @param childCount
     * @param i
     * @return
     */
    @Override
    protected int getChildDrawingOrder(int childCount, int i) {


        if (i == childCount - 1) {
            //最后的view直接返回mSearchBar的索引
            return mSearchBarIndex;
        } else if (i == childCount - 2) {
            //倒数第二的view直接返回mSuggestions的索引
            return mSuggestionsIndex;
        } else if (i < mSearchBarIndex && i < mSuggestionsIndex) {
            //view既在mSearchBar之前，又在mSuggestions之前
            return i;
        } else if (i >= mSearchBarIndex && i < (mSuggestionsIndex - 1)) {
            //view既在mSearchBar之后，又在mSuggestions之后返回计算后的位置
            return i + 1;
        } else if (i >= mSuggestionsIndex && i < (mSearchBarIndex - 1)) {
            return i + 1;
        } else {
            //剩下的都是介于两者之间
            return i + 2;
        }
    }





    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        //监听back按键事件
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            closeSearch();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }





    /**
     * 显示用与输入搜索的SearchView
     */
    public void openSearch() {
        displaySearchBar(true);
        displaySuggestions(true);
        AnimationUtils.createCircularReveal(mSearchBar, 200);
        InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.showSoftInput(mSearchView, InputMethodManager.SHOW_IMPLICIT);

    }





    /**
     * 关闭搜索界面
     */
    public void closeSearch() {
        mSearchView.setText("");
        InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(mSearchView.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
        AnimationUtils.createCircularHide(mSearchBar, 200, new AnimationUtils.OnHideAnimListener() {
            @Override
            public void onAnimationEnd() {
                displaySearchBar(false);
                displaySuggestions(false);
            }
        });
    }





    public void setSearchListener(SearchListener mSearchListener) {
        this.mSearchListener = mSearchListener;
    }





    /**
     * 你可以使SearchBar的Elevation属性与AppBarLayout同步,默认不同步,如果Elevation小于AppBarLayoutSearchBar将会被遮挡
     *
     * @param enable 启用将保证SearchBar可见,如果你想手动设置，请关闭它然后调用{@link #setSearchBarElevation(float)}
     */
    public void setAppBarLayoutElevationEnable(boolean enable) {
        this.mSearchBarElevationEnable = enable;
        invalidate();
    }





    /**
     * 设置SearchBar的阴影值
     *
     * @param elevation
     */
    public void setSearchBarElevation(float elevation) {
        mSearchBarElevation = elevation;
        ViewCompat.setElevation(mSearchBar, mSearchBarElevation);
    }





    /**
     * 设置搜索条的背景
     *
     * @param background 背景
     */
    public void setSearchBarBackground(Drawable background) {
        if (Build.VERSION.SDK_INT >= 16) {
            mSearchBar.setBackground(background);
        } else {
            mSearchBar.setBackgroundDrawable(background);
        }
    }





    /**
     * 设置背景色
     *
     * @param color 背景色
     */
    public void setSearchBarBackgroundColor(@ColorInt int color) {
        mSearchBar.setBackgroundColor(color);
    }





    /**
     * 设置背景色
     *
     * @param color 背景色资源
     */
    public void setSearchBarBackgroundColorRes(@ColorRes int color) {
        if (Build.VERSION.SDK_INT >= 23) {
            mSearchBar.setBackgroundColor(getResources().getColor(color, getContext().getTheme()));
        } else {
            mSearchBar.setBackgroundColor(getResources().getColor(color));
        }
    }





    public void setSearchTextColor(@ColorInt int color) {
        mSearchView.setTextColor(color);
    }





    public void setSearchTextColorRes(@ColorRes int color) {
        if (Build.VERSION.SDK_INT >= 23) {
            mSearchView.setTextColor(getResources().getColor(color, getContext().getTheme()));
        } else {
            mSearchView.setTextColor(getResources().getColor(color));
        }
    }





    public void setSearchTextColorStateList(ColorStateList colorStateList) {
        mSearchView.setTextColor(colorStateList);
    }





    /**
     * 设置背景资源
     *
     * @param res 背景资源
     */
    public void setSearchBarBackgroundRes(@DrawableRes int res) {
        mSearchBar.setBackgroundResource(res);
    }





    public void setBackImage(Drawable image) {
        mBackView.setImageDrawable(image);
    }





    public void setBackImageRes(@DrawableRes int imageRes) {
        mBackView.setImageResource(imageRes);
    }





    public void setBackImageBitmap(Bitmap imageBitmap) {
        mBackView.setImageBitmap(imageBitmap);
    }


//
//    @TargetApi(Build.VERSION_CODES.M)
//    public void setBackImageIcon(Icon icon) {
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//            mBackView.setImageIcon(icon);
//        }
//    }





    public void setBackTint(ColorStateList stateList) {
        Drawable backDrawable = mBackView.getDrawable();
        DrawableCompat.setTintList(backDrawable, stateList);
    }





    public void setBackTintColor(@ColorInt int color) {
        Drawable backDrawable = mBackView.getDrawable();
        DrawableCompat.setTint(backDrawable, color);
    }





    public void setBackMode(PorterDuff.Mode mode) {
        ViewCompat.setBackgroundTintMode(mBackView, mode);
    }





    public void setClearTint(ColorStateList stateList) {
        ViewCompat.setBackgroundTintList(mClearView, stateList);
    }





    public void setClearMode(PorterDuff.Mode mode) {
        ViewCompat.setBackgroundTintMode(mClearView, mode);
    }





    public void setClearImageRes(@DrawableRes int res) {
        mClearView.setImageResource(res);
    }





    public void setClearImageDrawable(Drawable drawable) {
        mClearView.setImageDrawable(drawable);
    }





    public void setClearImageBitmap(Bitmap bitmap) {
        mClearView.setImageBitmap(bitmap);
    }





    public void setSuggestionViewListener(SuggestionViewListener mSuggestionViewListener) {
        ListAdapter listAdapter = mSuggestionsListView.getAdapter();
        if (listAdapter != null && listAdapter instanceof SuggestionAdapter) {
            SuggestionAdapter suggestionAdapter = (SuggestionAdapter) listAdapter;
            suggestionAdapter.setSuggestionViewListener(mSuggestionViewListener);
            suggestionAdapter.notifyDataSetChanged();
        } else {
            SuggestionAdapter suggestionAdapter = new SuggestionAdapter(Collections.<Suggestion>emptyList());
            suggestionAdapter.setSuggestionViewListener(mSuggestionViewListener);
            mSuggestionsListView.setAdapter(suggestionAdapter);
        }
    }





    public void updateSuggestions(Collection<Suggestion> suggestions) {
        ListAdapter listAdapter = mSuggestionsListView.getAdapter();
        SuggestionAdapter suggestionAdapter;
        if (listAdapter != null && listAdapter instanceof SuggestionAdapter) {
            suggestionAdapter = (SuggestionAdapter) listAdapter;
            suggestionAdapter.setSuggestions(suggestions);
        } else {
            suggestionAdapter = new SuggestionAdapter(suggestions);
            mSuggestionsListView.setAdapter(suggestionAdapter);
        }
    }





    /**
     * 改变mSuggestionsListView的可见状态
     *
     * @param display 根据传入的display值,如果true将会将mSuggestionsListView的visibility值改变成{@link View#VISIBLE},
     *                否则将会设为{@link View#GONE}
     */
    private void displaySuggestions(boolean display) {
        mSuggestionsListView.setVisibility(display ? View.VISIBLE : View.GONE);
    }





    /**
     * 改变搜索条的可见状态
     *
     * @param display 根据传入的display值,如果true将会将mSearchBar的visibility值改变成{@link View#VISIBLE},
     *                否则将会设为{@link View#GONE}
     */
    private void displaySearchBar(boolean display) {
        mSearchBar.setVisibility(display ? View.VISIBLE : View.GONE);
    }





    /**
     * 改变清除按钮的可见状态
     *
     * @param display 根据传入的display值,如果true将会将mClearView的visibility值改变成{@link View#VISIBLE},
     *                否则将会设为{@link View#GONE}
     */
    private void displayClear(boolean display) {
        mClearView.setVisibility(display ? View.VISIBLE : View.GONE);
    }





    class DefaultSuggestionViewListener implements SuggestionViewListener {

        @Override
        public View getView(int position, final Suggestion suggestion, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;
            if (convertView == null) {
                convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.sample_suggestion_item, parent, false);
                viewHolder = new ViewHolder();
                viewHolder.text = (TextView) convertView.findViewById(R.id.text);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            viewHolder.text.setText(suggestion.getTitle());
            convertView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    v.getContext().startActivity(suggestion.getIntent());
                    closeSearch();
                }
            });
            return convertView;
        }





        class ViewHolder {
            TextView text;
        }
    }



    class DataSetObserverImpl extends DataSetObserver {
        @Override
        public void onChanged() {
            int count = mSuggestionsListView.getCount();
            displaySuggestions(count != 0);
        }
    }
}
